package no.ntnu.fp.utils;

import java.sql.Date;
import java.sql.Time;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import no.ntnu.fp.model.Appointment;
import no.ntnu.fp.model.MeetingRoom;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

public class MeetingRoomSchedule {
	private final Map<MeetingRoom, List<TimeInterval>> schedule = 
								new HashMap<MeetingRoom, List<TimeInterval>>();
	private Appointment appointment;

	public MeetingRoomSchedule(Map<MeetingRoom, List<TimeInterval>> schedule) {
		this.schedule.putAll(schedule);
	}
	
	public MeetingRoomSchedule(Element xml) {
		this.schedule.putAll(initializeFromXml(xml));
	}

	public List<MeetingRoom> getAllMeetingRooms() {
		return new ArrayList<MeetingRoom>(schedule.keySet());
	}
	
	public List<MeetingRoom> getAvailableMeetingRooms(TimeInterval timeInterval) {
		List<MeetingRoom> rooms = new ArrayList<MeetingRoom>();
		for (MeetingRoom room : schedule.keySet()) {
			if (isAvailable(room, timeInterval)) {
				rooms.add(room);
			}
		}
		return rooms;
	}
	
	public List<MeetingRoom> getUnavailableMeetingRooms(TimeInterval timeInterval) {
		List<MeetingRoom> allMeetingRooms = getAllMeetingRooms();
		allMeetingRooms.removeAll(getAvailableMeetingRooms(timeInterval));
		return allMeetingRooms;
	}
	
	public boolean isAvailable(MeetingRoom meetingRoom, TimeInterval timeInterval) {
		List<TimeInterval> intervals = schedule.get(meetingRoom);
		intervals.remove(getAppointmentInterval());
		if (intervals != null) {
			for (TimeInterval interval: intervals) {
				if (interval.intersects(timeInterval)) {
					return false;
				}
			}
		}
		return true;
	}

	private TimeInterval getAppointmentInterval() {
		if (appointment != null) {
			Date date = appointment.getDate();
			Time startTime = appointment.getStartTime(),
				endTime = appointment.getEndTime();
			
			return new TimeInterval(date, startTime, endTime);
		} else {
			return null;
		}
	}

	public Element toXml(Document doc) {
		Element scheduleElement = doc.createElement("schedule");
		for (Entry<MeetingRoom, List<TimeInterval>> entry: schedule.entrySet()) {
			Element entryElement = doc.createElement("entry");
			entryElement.appendChild(entry.getKey().toXml(doc));
			
			Element intervalsElement = doc.createElement("intervals");
			for (TimeInterval interval: entry.getValue()) {
				intervalsElement.appendChild(interval.toXml(doc));
			}
			entryElement.appendChild(intervalsElement);
			scheduleElement.appendChild(entryElement);
		}
		return scheduleElement;
	}
	
	private Map<MeetingRoom, List<TimeInterval>> initializeFromXml(Element xml) {
		Map<MeetingRoom, List<TimeInterval>> map 
							= new HashMap<MeetingRoom, List<TimeInterval>>();
		
		NodeList entries = xml.getElementsByTagName("entry");
		for (int i = 0; i < entries.getLength(); i++) {
			Element entryElement = (Element)entries.item(i);
			
			Element meetingRoomElement 
			= (Element)entryElement.getElementsByTagName("meetingroom").item(0);
			MeetingRoom meetingRoom = new MeetingRoom(meetingRoomElement);
			
			NodeList intervals = entryElement.getElementsByTagName("interval");
			List<TimeInterval> intervalList = new ArrayList<TimeInterval>();
			for (int j = 0; j < intervals.getLength(); j++) {
				Element intervalElement = (Element)intervals.item(j);
				intervalList.add(new TimeInterval(intervalElement));
			}
			
			map.put(meetingRoom, intervalList);
		}
		
		return map;
	}

	public void setAppointment(Appointment appointment) {
		this.appointment = appointment;
	}
}
